package com.randi.file.utils;

import com.randi.common.config.AppConfig;
import com.randi.common.enums.ResultCode;
import com.randi.common.exception.ServiceException;
import com.randi.common.utils.StringUtils;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.math.BigInteger;
import java.util.*;

/**
 * @author ziye
 */
@Component
public class SysFileUtils {

    private static String DEFAULT_BASE_DIR;

    public static final String SEPARATOR = "/";

    @Resource
    private void init(AppConfig.FileConfig fileConfig) {
        DEFAULT_BASE_DIR = fileConfig.getPath();
    }

    /**
     * 获取绝对路径
     *
     * @param pathName 文件路径
     * @return 绝对路径
     */
    public static String getBasePath(String pathName) {
        if (StringUtils.isEmpty(pathName)) {
            return DEFAULT_BASE_DIR;
        }
        if (!pathName.startsWith(SEPARATOR)) {
            pathName = SEPARATOR + pathName;
        }
        return StringUtils.format("{}{}", DEFAULT_BASE_DIR, pathName);
    }

    /**
     * 获取文件信息
     *
     * @param pathName 文件路径
     * @return 文件信息
     */
    public static File getFile(String pathName) {
        if (StringUtils.isNotEmpty(pathName)) {
            String filePath = getBasePath(pathName);
            return new File(filePath);
        }
        return null;
    }

    /**
     * 获取文件夹对象
     *
     * @param pathName pathName
     * @return 文件夹对象
     */
    public static File getFolder(String pathName) {
        if (StringUtils.isNotEmpty(pathName)) {
            String filePath = getBasePath(pathName);
            File folder = new File(filePath);
            return folder.isDirectory() ? folder : null;
        }
        return null;
    }

    /**
     * 文件是否存在
     *
     * @param file 文件对象
     * @return 结果
     */
    public static boolean fileExist(File file) {
        return file != null && file.exists() && file.isFile();
    }

    /**
     * 文件是否存在
     *
     * @param pathName 文件路径
     * @return 结果
     */
    public static boolean fileExist(String pathName) {
        File file = getFile(pathName);
        return fileExist(file);
    }

    /**
     * 文件是否存在
     *
     * @param folder 文件夹对象
     * @return 结果
     */
    public static boolean folderExist(File folder) {
        return folder != null && folder.exists() && folder.isDirectory();
    }

    /**
     * 文件是否存在
     *
     * @param pathName 文件路径
     * @return 结果
     */
    public static boolean folderExist(String pathName) {
        File folder = getFolder(pathName);
        return folderExist(folder);
    }

    /**
     * 创建文件
     *
     * @param pathName 文件路径
     */
    public static void createFile(String pathName) {
        if (StringUtils.isEmpty(pathName)) {
            throw new IllegalArgumentException("文件路径不能为空");
        }
        try {
            String filePath = getBasePath(pathName);
            File file = new File(filePath);
            if (!fileExist(file)) {
                FileUtils.touch(file);
            }
        } catch (IOException ignored) {
        }
    }

    /**
     * 创建文件夹
     *
     * @param pathName 文件路径
     */
    public static void createFolder(String pathName) {
        try {
            String filePath = getBasePath(pathName);
            File folder = new File(filePath);
            if (!folderExist(folder)) {
                FileUtils.forceMkdir(folder);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 删除文件
     *
     * @param file 文件对象
     */
    public static void deleteFile(File file) {
        try {
            if (fileExist(file)) {
                FileUtils.forceDelete(file);
            }
        } catch (IOException ignored) {
        }
    }

    /**
     * 删除文件
     *
     * @param pathName 文件路径
     */
    public static void deleteFile(String pathName) {
        if (StringUtils.isNotEmpty(pathName)) {
            File file = new File(pathName);
            deleteFile(file);
        }
    }

    /**
     * 删除文件夹
     *
     * @param folder 文件夹对象
     */
    public static void deleteFolder(File folder) {
        try {
            if (folderExist(folder)) {
                FileUtils.deleteDirectory(folder);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 删除文件夹
     *
     * @param pathName 文件路径
     */
    public static void deleteFolder(String pathName) {
        if (StringUtils.isNotEmpty(pathName)) {
            File folder = new File(pathName);
            deleteFolder(folder);
        }
    }

    /**
     * 获取文件大小
     *
     * @param file 文件信息
     * @return 文件大小
     */
    public static BigInteger getFileSize(File file) {
        return fileExist(file) ? FileUtils.sizeOfAsBigInteger(file) : BigInteger.ZERO;
    }

    /**
     * 获取文件大小
     *
     * @param pathName 文件路径
     * @return 文件大小
     */
    public static BigInteger getFileSize(String pathName) {
        File file = getFile(pathName);
        if (file != null) {
            return getFileSize(file);
        }
        return BigInteger.ZERO;
    }

    /**
     * 获取文件大小
     *
     * @param folder 文件夹对象
     * @return 文件大小
     */
    public static BigInteger getFolderSize(File folder) {
        if (folderExist(folder)) {
            return Arrays.stream(Objects.requireNonNull(folder.listFiles()))
                    .map(FileUtils::sizeOfAsBigInteger)
                    .reduce(BigInteger::add)
                    .orElse(BigInteger.ZERO);
        }
        return BigInteger.ZERO;
    }

    /**
     * 获取文件大小
     *
     * @param pathName 文件路径
     * @return 文件大小
     */
    public static BigInteger getFolderSize(String pathName) {
        File folder = getFolder(pathName);
        if (folder != null) {
            return getFolderSize(folder);
        }
        return BigInteger.ZERO;
    }

    /**
     * 获取文件流
     *
     * @param file 文件
     * @throws IOException 异常
     */
    public static byte[] readFileBytes(File file) throws IOException {
        return FileUtils.readFileToByteArray(file);
    }

    /**
     * 文件下载
     *
     * @param response 响应对象
     * @param pathName 文件路径
     * @param fileName 文件名称
     */
    public static void download(HttpServletResponse response, String pathName, String fileName) {
        File file = getFile(pathName);

        if (!fileExist(file)) {
            throw new ServiceException(ResultCode.FILE_DOWNLOAD_FAIL);
        }

        // 设置文件响应流参数
        response.setContentType("application/octet-stream");
        response.setHeader("Content-Disposition", "attachment;filename=" + fileName);
        ServletOutputStream outputStream = null;
        try {
            // 读取文件并写入响应流
            outputStream = response.getOutputStream();
            outputStream.write(SysFileUtils.readFileBytes(file));
        } catch (Exception e) {
            throw new ServiceException(ResultCode.FILE_DOWNLOAD_FAIL);
        } finally {
            IOUtils.closeQuietly(outputStream);
        }
    }

    /**
     * 预览文件
     *
     * @param response 响应对象
     * @param pathName 文件路径
     * @param fileName 文件名称
     */
    public static void preview(HttpServletResponse response, String pathName, String fileName) {
        File file = getFile(pathName);
        if (!fileExist(file)) {
            return;
        }
        // 设置文件响应流参数
        response.setContentType("application/octet-stream");
        response.setHeader("Content-Disposition", "attachment;filename=" + fileName);
        ServletOutputStream outputStream = null;
        try {
            byte[] bytes = SysFileUtils.readFileBytes(file);
            // 读取文件并写入响应流
            outputStream = response.getOutputStream();
            outputStream.write(bytes);
        } catch (Exception ignored) {
        } finally {
            IOUtils.closeQuietly(outputStream);
        }
    }

}
